package reliability;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import reliability.model.GraphModel;
import reliability.types.Settings;
import reliability.types.graph.Edge;
import reliability.types.graph.Node;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;

public class XmlBuilder
{
    private Document document;
    private GraphModel model;

    public void buildXmlFromModel(GraphModel model, File file)
    {
        this.model = model;
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        try
        {
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            document = documentBuilder.newDocument();
            createDomTree();
            OutputFormat format = new OutputFormat(document);
            format.setIndenting(true);
            format.setIndent(2);
            XMLSerializer xmlSerializer = new XMLSerializer(new FileOutputStream(file), format);
            xmlSerializer.serialize(document);
        }
        catch (ParserConfigurationException parserConfigurationException)
        {
            parserConfigurationException.printStackTrace();
        }
        catch (IOException ioException)
        {
            ioException.printStackTrace();
        }
    }

    private void createDomTree()
    {
        Element rootElement = document.createElement(XmlParser.CONFIGURATION_TAG_NAME);
        rootElement.appendChild(createSettingsElement());
        rootElement.appendChild(createGraphElement());
        document.appendChild(rootElement);
    }

    private Element createSettingsElement()
    {
        Element settingsElement = document.createElement(XmlParser.SETTINGS_TAG_NAME);
        Settings settings = model.getSettings();

        Element defaultNodeReliabilityElement = document.createElement(XmlParser.DEFAULT_NODE_RELIABILITY_TAG_NAME);
        defaultNodeReliabilityElement.setTextContent(formatDoubleValue(settings.defaultNodeReliability));

        Element defaultEdgeReliabilityElement = document.createElement(XmlParser.DEFAULT_EDGE_RELIABILITY_TAG_NAME);
        defaultEdgeReliabilityElement.setTextContent(formatDoubleValue(settings.defaultEdgeReliability));

        Element numberOfTestsElement = document.createElement(XmlParser.NUMBER_OF_TESTS_TAG_NAME);
        numberOfTestsElement.setTextContent(Integer.toString(settings.numberOfTests));

        settingsElement.appendChild(defaultNodeReliabilityElement);
        settingsElement.appendChild(defaultEdgeReliabilityElement);
        settingsElement.appendChild(numberOfTestsElement);
        return settingsElement;
    }

    private Element createGraphElement()
    {
        Element graphElement = document.createElement(XmlParser.GRAPH_TAG_NAME);
        graphElement.appendChild(createNodesElement());
        graphElement.appendChild(createEdgesElement());
        return graphElement;
    }

    private Element createNodesElement()
    {
        Element nodesElement = document.createElement(XmlParser.NODES_TAG_NAME);
        for (Map.Entry<Integer, Node> nodeEntry : model.getNodes().entrySet())
        {
            Node node = nodeEntry.getValue();
            Element nodeElement = document.createElement(XmlParser.NODE_TAG_NAME);
            nodeElement.setAttribute(XmlParser.INDEX_ATTRIBUTE_NAME, nodeEntry.getKey().toString());
            nodeElement.setAttribute(XmlParser.RELIABILITY_ATTRIBUTE_NAME, formatDoubleValue(node.getReliability()));
            nodeElement.setAttribute(XmlParser.X_ATTRIBUTE_NAME, Integer.toString(node.getColumn()));
            nodeElement.setAttribute(XmlParser.Y_ATTRIBUTE_NAME, Integer.toString(node.getRow()));
            nodesElement.appendChild(nodeElement);
        }
        return nodesElement;
    }

    private Element createEdgesElement()
    {
        Element edgesElement = document.createElement(XmlParser.EDGES_TAG_NAME);
        for (Map.Entry<Integer, Edge> edgeEntry : model.getEdges().entrySet())
        {
            Edge edge = edgeEntry.getValue();
            Element edgeElement = document.createElement(XmlParser.EDGE_TAG_NAME);
            edgeElement.setAttribute(XmlParser.INDEX_ATTRIBUTE_NAME, edgeEntry.getKey().toString());
            edgeElement.setAttribute(XmlParser.RELIABILITY_ATTRIBUTE_NAME, formatDoubleValue(edge.getReliability()));
            edgeElement.setAttribute(XmlParser.NODE1_ATTRIBUTE_NAME, edge.getNode1Key().toString());
            edgeElement.setAttribute(XmlParser.NODE2_ATTRIBUTE_NAME, edge.getNode2Key().toString());
            edgesElement.appendChild(edgeElement);
        }
        return edgesElement;
    }

    private String formatDoubleValue(double value)
    {
        String doubleStr = Double.toString(value);
        return doubleStr.replace('.', ',');
    }

}
